package capr;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.net.URISyntaxException;
import java.net.URL;

import capr.camera.CameraControl;
import capr.control.ModelControl;
import capr.model.ControlAnimation;
import capr.model.LoadMD5Animation;
import capr.model.LoadMD5Mesh;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingSphere;
import com.jme.input.KeyInput;
import com.jme.light.DirectionalLight;
import com.jme.light.PointLight;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.state.LightState;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;
import com.md5importer.interfaces.model.IMD5Anim;
import com.md5importer.interfaces.model.IMD5Node;

/** 
 * @author Ludwig Lienkamp 
 * @author Daniel Ahrens
 * @author Daniel Erpilev
 * @author	Gina Wagner
 * @author Jens Griesinger
 * @author Stefan Knebel 
 * @version v.1.0.0
 *  
 * this Class is the Main Class of this Program
 */

public class Iwalktheline extends SimpleGame {
	
	private LoadMD5Mesh loadMesh;
	private LoadMD5Animation loadAnim;
	private IMD5Node mesh, ground, wall, boxes;
	private Node character, world;
	private IMD5Anim standAnimation, walkAnimation, runAnimation, turnLeftAnimation, turnRightAnimation, backwardsAnimation;
	private ControlAnimation controlAnim;
    private CameraControl camera;  
    
	@SuppressWarnings("unused")
	private static float gravity = 8.0f;
   
    private boolean simulateKey = false;
    
    public static void main(String[] args) {
    	
    	//Create Object
    	Iwalktheline app = new Iwalktheline();  

    	//own logo
        app.setConfigShowMode(ConfigShowMode.AlwaysShow, Iwalktheline.class.getClassLoader().getResource("capr/data/iwalktheline.png"));
        
        //Start the program
        app.start();
    }
    
	protected void simpleUpdate() {	
		
		mesh.swapBuffers();
		
		camera.getChaser().update(tpf);
		
		characterAction();
	}
	

    /**
     * Ludwig Lienkamp, Jens Griesinger <br>
     * 
     * if the characternode intersects a wall it simulates a keypress and the character runs in the other direction
     */
	protected void characterAction() {
		
	    Robot robot;
	    
		try {
			
			robot = new Robot();
			
			//if no barrier in the way
			if(!intersect(boxes) && !intersect(wall)) {	
			
				if(simulateKey) {
				
					//release the simulate keypress
					robot.keyRelease(KeyEvent.VK_DOWN);
					robot.keyRelease(KeyEvent.VK_UP);
					
					input.setActionSpeed(5f, "turnRight");
					input.setActionSpeed(5f, "turnLeft");
					
					simulateKey = false;
				}
			
				switchAnimation();
			}
			
			else {		
				
				if(KeyInput.get().isKeyDown(KeyInput.KEY_UP) && !simulateKey) {
		
					//simulate keypress
					robot.keyPress(  KeyEvent.VK_DOWN );
					
					input.setActionSpeed(0f, "turnRight");
					input.setActionSpeed(0f, "turnLeft");
				        
					simulateKey = true;
				}
				
				if(KeyInput.get().isKeyDown(KeyInput.KEY_DOWN) && !simulateKey) {
					
					//simulate keypress
					robot.keyPress(  KeyEvent.VK_UP  );
					
					input.setActionSpeed(0f, "turnRight");
					input.setActionSpeed(0f, "turnLeft");
				        
					simulateKey = true;
				} 
			
		}
		
		if(!intersect(ground)) {
			
		}
			
		else {
			
			//	collision(ground);
		}
		
		} catch (AWTException e) {
			
			e.printStackTrace();
		}
	}
	
    /**
     * Ludwig Lienkamp, Stefan Knebel <br>
     * 
     * sets the animation on the basis of the keypress
     */
	protected void switchAnimation() {	
					 
		//run forward animation
		if(KeyInput.get().isKeyDown(KeyInput.KEY_UP) && KeyInput.get().isKeyDown(KeyInput.KEY_W)) {
		
			if(!controlAnim.getActiveAnimation().equals(runAnimation)) {
				
				//morph inside the new animation
				controlAnim.morphAnimation(runAnimation);
				
				input.setActionSpeed(20f, "forward");
				
				//same speed for backward to run equal fast with the simulated key
				input.setActionSpeed(20f, "backward");
				
				//set animation
				controlAnim.setAnimation(runAnimation);
					
				//start animation - thread
				controlAnim.startAnimation();
			}
			
		} else 
				
			//walk forward animation
			if(KeyInput.get().isKeyDown(KeyInput.KEY_UP)) {
				
				if(!controlAnim.getActiveAnimation().equals(walkAnimation)) {

				//	input.setActionSpeed(0f, "forward");
					
					controlAnim.morphAnimation(walkAnimation);
					
					input.setActionSpeed(10f, "forward");
					
					//set animation
					controlAnim.setAnimation(walkAnimation);
					
					//start animation - thread
					controlAnim.startAnimation();	
				}
					
			} else
				
				//walk backward animation
				if(KeyInput.get().isKeyDown(KeyInput.KEY_DOWN)) {
						
					if(!controlAnim.getActiveAnimation().equals(backwardsAnimation)) {
						
							
						input.setActionSpeed(0f, "backward");
						
						controlAnim.morphAnimation(backwardsAnimation);
						
						input.setActionSpeed(10f, "backward");
		
						//set animation
						controlAnim.setAnimation(backwardsAnimation);
					
						//start animation - thread
						controlAnim.startAnimation();
					}
						
				} else
				
					//turn right animation
					if(KeyInput.get().isKeyDown(KeyInput.KEY_RIGHT)) {
					
						if(!controlAnim.getActiveAnimation().equals(turnRightAnimation)) {
								
							controlAnim.morphAnimation(turnRightAnimation);		
							
							//set animation
							controlAnim.setAnimation(turnRightAnimation);
					
							//start animation - thread
							controlAnim.startAnimation();
						}
							
					} else
				
						//turn left animation
						if(KeyInput.get().isKeyDown(KeyInput.KEY_LEFT)) {
					
							if(!controlAnim.getActiveAnimation().equals(turnLeftAnimation)) {
									
								controlAnim.morphAnimation(turnLeftAnimation);
								
								//set animation
								controlAnim.setAnimation(turnLeftAnimation);
					
								//start animation - thread
								controlAnim.startAnimation();
							}
								
						} else 
				
							//stand at point animation
							if(!controlAnim.getActiveAnimation().equals(standAnimation)) {
									
								controlAnim.morphAnimation(standAnimation);
								
								//set animation
								controlAnim.setAnimation(standAnimation);
					
								//start animation - thread
								controlAnim.startAnimation();
							}
	}
	
    /**
     * Ludwig Lienkamp, Daniel Erpilev 
     */
    @Override
    protected void simpleInitGame() {
    	
    	display.setTitle("i walk the line");
    	
    	//to use the relative path of the texture
    	overrideTextureKey();
    	
    	initModels();  
    	
    	character.setLocalTranslation(13, 0, 10);
    	
    	initCamera();
    	
    	initInput();
    	
    	initLight();
		
		//put it on the screen graph
		rootNode.attachChild(character);
		rootNode.attachChild(world);
    }
    
    /**
     * Daniel Ahrens, Ludwig Lienkamp <br>
     * 
     * search collision of two nodes
     * 
     * @param node	IMD5Node
     * @return hit	boolean that represents the collision information
     */
    protected boolean intersect(IMD5Node node) {
    	
    	boolean hit = false;
    	
    	//only the Childnodes, not the Boundingbox of the Node!
    	int numOfChilds = ((Node)node).getChildren().size();
    	
    	//all childes
    	for (int i = 0; i < numOfChilds; i++) {
    		
    		//search collision of character and all objects at the node
    		if(character.getWorldBound().intersects(((Node)node).getChild(i).getWorldBound())) {
    			
    			hit = true;
    			
    			return hit;
    		}
    		else
    			hit = false;	
    	}
    	
    	return hit;
    }
    
    /**
     * Daniel Erpilev
     * 
     * this class creates a cameraControl
     */
    protected void initCamera() {
    	
    	camera = new CameraControl();

    	camera.buildChaseCamera(character, cam);
    }

    protected void initInput() {
    	
    	input = new ModelControl(character, 15f, 5f);
    }
    
    /**
     * Daniel Erpiev, Ludwig Lienkamp <br>
     * 
     * load the model, cut the animation, and let it move on a point
     *
     */
    
    protected void initModels() {
        
    	//load Character
    	loadMesh = new LoadMD5Mesh();
		
		mesh = loadMesh.loadMesh("walk_v2.1.md5Mesh");

		character = new Node("character Node");
		
		character.attachChild((Node)mesh);
		character.setLocalScale(3.0f);
		
		//use a boundingSphere, because the boundingBox "flicker" and than the collision work incorrect
		character.setModelBound(new BoundingSphere());
		character.updateModelBound();
		
		//load Animations
		loadAnim = new LoadMD5Animation();
		
		//load animations
		standAnimation 		= loadAnim.loadAnimation("standing_v2.1.md5Anim");
		walkAnimation  		= loadAnim.loadAnimation("walk_v2.1.md5Anim");
		runAnimation		= loadAnim.loadAnimation("run_v1.md5Anim");
		turnLeftAnimation	= loadAnim.loadAnimation("turnleft_v1.md5Anim");
		turnRightAnimation	= loadAnim.loadAnimation("turnright_v1.md5Anim");
		backwardsAnimation	= loadAnim.loadAnimation("walk_backw.md5Anim");
		
    	controlAnim = new ControlAnimation(mesh);
    	
    	//add animation into a array
    	controlAnim.addAnimation(standAnimation);
    	controlAnim.addAnimation(walkAnimation);
    	controlAnim.addAnimation(runAnimation);
    	controlAnim.addAnimation(turnLeftAnimation);
    	controlAnim.addAnimation(turnRightAnimation);
    	controlAnim.addAnimation(backwardsAnimation);
		
    	controlAnim.stayAtPoint(standAnimation);
    	controlAnim.stayAtPoint(walkAnimation);
    	controlAnim.stayAtPoint(runAnimation);
    	controlAnim.stayAtPoint(turnLeftAnimation);
    	controlAnim.stayAtPoint(turnRightAnimation);
    	controlAnim.stayAtPoint(backwardsAnimation);
    	
		//take a part of the animation
    	controlAnim.cutAnimation(0, 50, 74);
		
		controlAnim.cutAnimation(1, 0, 128);
		
		controlAnim.cutAnimation(2, 8, 104);
		
	//	controlAnim.cutAnimation(3, 70, 100);
		
	//	controlAnim.cutAnimation(4, 70, 100);
		
		controlAnim.cutAnimation(5, 150, 370);
		
		
		//set animation
		controlAnim.setAnimation(standAnimation);
		
		//start animation - thread
		controlAnim.startAnimation();
		
		//load World
		ground 	= loadMesh.loadMesh("ground_v2.md5Mesh");
		
		((Node)ground).setLocalTranslation(0, 0.1f, 0);
		
		boxes	= loadMesh.loadMesh("boxes_v2.md5Mesh");
		
		wall	= loadMesh.loadMesh("bounding_v3_2.md5Mesh");

		world = new Node("World Node");
		
		//cast IMD5Node to Node and put it on the World-Node
		world.attachChild((Node)ground);
		world.attachChild((Node)wall);
		world.attachChild((Node)boxes);
		
		world.setLocalScale(1.3f);
		
		world.updateModelBound();
    }
	
    // http://www.jmonkeyengine.com/forum/index.php?topic=9482.0
	protected void overrideTextureKey() {
		
		try {
			URL url = this.getClass().getClassLoader().getResource("capr/model/data/mesh/texture/");
			SimpleResourceLocator locator = new SimpleResourceLocator(url);
			ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_TEXTURE, locator);
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}
    
    /**
     * Gina Wagner, Tobias Bindler <br>
     * 
     * set light
     */
    protected void initLight() {
    	
    	//ls1 with DirectionalLight has to be attached to World Node
    	LightState ls1 = display.getRenderer().createLightState();
    	 
    	DirectionalLight dl = new DirectionalLight();
    	dl.setDirection(new Vector3f(-1, -1, -1));
    	dl.setEnabled(true);
    	 
    	ls1.attach(dl);
    
    	world.setRenderState(ls1);
    	 
    	//ls2 with PointLight has to be attached to Player-Node
    	LightState ls2 = display.getRenderer().createLightState();
    	 
    	PointLight pl = new PointLight();
    	pl.setLocation(new Vector3f(1, 1, 1));
    	pl.setEnabled(true);
    	 
    	ls2.attach(pl);
    	
    	character.setRenderState(ls2);
    }
}
